<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
 <head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>子组(子模式)</title>
<link media="all" rel="stylesheet" type="text/css" href="styles/03e73060321a0a848018724a6c83de7f-theme-base.css" />
<link media="all" rel="stylesheet" type="text/css" href="styles/03e73060321a0a848018724a6c83de7f-theme-medium.css" />

 </head>
 <body class="docs"><div class="navbar navbar-fixed-top">
  <div class="navbar-inner clearfix">
    <ul class="nav" style="width: 100%">
      <li style="float: left;"><a href="regexp.reference.internal-options.html">« 内部选项设置</a></li>
      <li style="float: right;"><a href="regexp.reference.repetition.html">重复/量词 »</a></li>
    </ul>
  </div>
</div>
<div id="breadcrumbs" class="clearfix">
  <ul class="breadcrumbs-container">
    <li><a href="index.html">PHP Manual</a></li>
    <li><a href="reference.pcre.pattern.syntax.html">PCRE 正则语法</a></li>
    <li>子组(子模式)</li>
  </ul>
</div>
<div id="layout">
  <div id="layout-content"><div id="regexp.reference.subpatterns" class="section">
  <h2 class="title">子组(子模式)</h2>
  <p class="para">
  子组通过圆括号分隔界定，并且它们可以嵌套。
  将一个模式中的一部分标记为子组(子模式)主要是来做两件事情：
  </p>
  <ol type="1">
   <li class="listitem">
    <p class="para">
    将可选分支局部化。比如，模式<code class="literal">cat(arcat|erpillar|)</code>匹配 ”cat”， “cataract”，
    “caterpillar” 中的一个，如果没有圆括号的话，它匹配的则是 ”cataract”，
    “erpillar” 以及空字符串。
    </p>
   </li>
   <li class="listitem">
    <p class="para">
    将子组设定为捕获子组(向上面定义的)。当整个模式匹配后，
    目标字符串中匹配子组的部分将会通过 <span class="function"><strong>pcre_exec()()</strong></span>
     的 <em class="emphasis">ovector</em> 参数回传给调用者。
    左括号从左至右出现的次序就是对应子组的下标(从 1 开始)，
    可以通过这些下标数字来获取捕获子模式匹配结果。
    </p>
   </li>
  </ol>
  <p class="para">
  比如，如果字符串 ”the red king” 使用模式<code class="literal">((red|white)
  (king|queen))</code> 进行匹配，
  模式匹配到的结果是 array(“red king”， ”red king”, “red”, “king”) 的形式，
  其中第 0 个元素是整个模式匹配的结果，后面的三个元素依次为三个子组匹配的结果。
  它们的下标分别为 1， 2， 3。
  </p>
  <p class="para">
  事实上，并不一定同时需要圆括号的两种功能。
  经常我们会需要子组进行分组， 但又不需要(单独的)捕获它们。
  在子组定义的左括号后面紧跟字符串 ”?:” 会使得该子组不被单独捕获，
  并且不会对其后子组序号的计算产生影响。比如, 如果字符串 &quot;the white queen&quot;
  匹配模式 <code class="literal">the ((?:red|white) (king|queen))</code>，
   匹配到的子串是 &quot;white queen&quot; 和 &quot;queen&quot;，
  他们的下标分别是 1 和 2。
   捕获子组的最大序号为 65535。然而由于 libpcre 的配置，我们可能无法编译这么长的
  正则表达式。
  </p>
  <p class="para">
  为了方便简写，如果需要在非捕获子组开始位置设置选项，
  选项字母可以位于 ? 和 : 之间，比如两个模式：
  </p>
  
  <div class="informalexample">
   <div class="example-contents">
<div class="cdata"><pre>
(?i:saturday|sunday)
(?:(?i)saturday|sunday)
</pre></div>
   </div>

  </div>
  
  <p class="para">
  匹配到了完全相同的字符集。因为可选分支会从左到右尝试每个分支，
  并且选项没有在子模式结束前被重置，
  并且由于选项的设置会穿透对后面的其他分支产生影响，因此，
  上面的模式都会匹配 ”SUNDAY” 以及 ”Saturday”。
  </p>

  <p class="para">
  可以对子组使用 <code class="literal">(?P&lt;name&gt;pattern)</code> 的语法进行命名。
  这个子模式将会在匹配结果中同时以其名称和顺序(数字下标)出现，
  还有两种为子组命名的语法：
  <code class="literal">(?&lt;name&gt;pattern)</code> 和 <code class="literal">(?&#039;name&#039;pattern)</code>。
  </p>

  <p class="para">
  有时需要多个匹配可以在一个正则表达式中选用子组。
  为了让多个子组可以共用一个后向引用数字的问题，
  <code class="literal">(?|</code> 语法允许复制数字。
  考虑下面的正则表达式匹配<code class="literal">Sunday</code>：
  </p>

  <div class="informalexample">
   <div class="example-contents">
<div class="cdata"><pre>(?:(Sat)ur|(Sun))day</pre></div>
   </div>

  </div>

  <p class="para">
  这里当后向引用 1 空时<code class="literal">Sun</code> 存储在后向引用 2 中。
  当后向引用 2 不存在的时候 <code class="literal">Sat</code> 存储在后向引用 1中。 使用
  <code class="literal">(?|</code>修改模式来修复这个问题：
  </p>

  <div class="informalexample">
   <div class="example-contents">
<div class="cdata"><pre>(?|(Sat)ur|(Sun))day</pre></div>
   </div>

  </div>

  <p class="para">
  使用这个模式，
  <code class="literal">Sun</code> 和 <code class="literal">Sat</code> 都会被存储到后向引用 1 中。
  </p>
 </div></div></div></body></html>